#!/usr/bin/env python3
# -*- coding: utf-8 -*-

import os
import sys
import json
import re
import random
import requests
from datetime import datetime, timedelta
from collections import Counter
import logging
from logging.handlers import RotatingFileHandler

# 添加当前目录到Python路径
current_dir = os.path.dirname(os.path.abspath(__file__))
sys.path.insert(0, current_dir)

try:
    from flask import Flask, request, jsonify, Blueprint
    from flask_sqlalchemy import SQLAlchemy
    from flask_jwt_extended import JWTManager, create_access_token, jwt_required, get_jwt_identity
    from flask_cors import CORS
    from werkzeug.security import generate_password_hash, check_password_hash
    from sqlalchemy import func
    import pymysql
    from bs4 import BeautifulSoup
except ImportError as e:
    print(f"缺少依赖包: {e}")
    print("请运行: pip install flask flask-sqlalchemy flask-jwt-extended flask-cors pymysql beautifulsoup4")
    sys.exit(1)

def main():
    app = Flask(__name__)
    
    # 配置
    app.config['SECRET_KEY'] = 'your-secret-key-here'
    app.config['SQLALCHEMY_DATABASE_URI'] = 'mysql+pymysql://root:mario@localhost/ai_ssq?charset=utf8mb4'
    app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False
    app.config['JWT_SECRET_KEY'] = 'jwt-secret-string'
    app.config['JWT_TOKEN_LOCATION'] = ['headers']
    app.config['JWT_HEADER_NAME'] = 'Authorization'
    app.config['JWT_HEADER_TYPE'] = 'Bearer'
    
    # 初始化扩展
    db = SQLAlchemy(app)
    jwt = JWTManager(app)
    CORS(app)
    
    # 配置日志
    if not os.path.exists('logs'):
        os.mkdir('logs')
    file_handler = RotatingFileHandler('logs/ai_ssq.log', maxBytes=10240, backupCount=10)
    file_handler.setFormatter(logging.Formatter(
        '%(asctime)s %(levelname)s: %(message)s [in %(pathname)s:%(lineno)d]'
    ))
    file_handler.setLevel(logging.INFO)
    app.logger.addHandler(file_handler)
    app.logger.setLevel(logging.INFO)
    app.logger.info('AI双色球分析助手启动')
    
    # 辅助函数
    def get_next_draw_number(end_draw):
        """获取下一期期号"""
        if not end_draw or len(end_draw) < 7:
            return ''
        year = end_draw[:4]
        number = int(end_draw[4:])
        return f"{year}{(number + 1):03d}"
    
    def calculate_win_level(red_matches, blue_match, prize_info=None):
        """计算中奖等级和金额"""
        if red_matches == 6 and blue_match:
            level = 1
        elif red_matches == 6 and not blue_match:
            level = 2
        elif red_matches == 5 and blue_match:
            level = 3
        elif red_matches == 5 and not blue_match:
            level = 4
        elif red_matches == 4 and blue_match:
            level = 4
        elif red_matches == 4 and not blue_match:
            level = 5
        elif red_matches == 3 and blue_match:
            level = 5
        elif red_matches == 2 and blue_match:
            level = 6
        elif red_matches == 1 and blue_match:
            level = 6
        elif red_matches == 0 and blue_match:
            level = 6
        else:
            return 0, 0
        
        if prize_info:
            try:
                prize_data = json.loads(prize_info) if isinstance(prize_info, str) else prize_info
                for prize in prize_data:
                    if prize.get('type') == level:
                        return level, float(prize.get('typemoney', 0))
            except:
                pass
        
        default_prizes = {
            1: 5000000, 2: 100000, 3: 3000, 4: 200, 5: 10, 6: 5
        }
        return level, default_prizes.get(level, 0)
    
    def analyze_red_ball_exclusion(lottery_data):
        """分析红球互斥关系"""
        try:
            # 统计每个红球号码的出现次数
            ball_counts = {}
            for i in range(1, 34):
                ball_counts[i] = 0
            
            # 统计每对红球号码的共现次数
            co_occurrence = {}
            for i in range(1, 34):
                for j in range(i + 1, 34):
                    co_occurrence[(i, j)] = 0
            
            # 分析每期数据
            for draw in lottery_data:
                red_balls = [draw.red_ball_1, draw.red_ball_2, draw.red_ball_3, 
                           draw.red_ball_4, draw.red_ball_5, draw.red_ball_6]
                
                # 统计单个号码出现次数
                for ball in red_balls:
                    ball_counts[ball] += 1
                
                # 统计号码对共现次数
                for i in range(len(red_balls)):
                    for j in range(i + 1, len(red_balls)):
                        ball1, ball2 = min(red_balls[i], red_balls[j]), max(red_balls[i], red_balls[j])
                        co_occurrence[(ball1, ball2)] += 1
            
            total_draws = len(lottery_data)
            
            # 计算互斥关系
            exclusion_relationships = []
            strong_exclusions = []  # 强互斥（从未一起出现）
            weak_exclusions = []    # 弱互斥（很少一起出现）
            
            for (ball1, ball2), co_count in co_occurrence.items():
                ball1_count = ball_counts[ball1]
                ball2_count = ball_counts[ball2]
                
                # 计算期望共现次数（基于独立假设）
                expected_co = (ball1_count * ball2_count) / total_draws
                
                # 计算互斥强度
                if co_count == 0:
                    # 从未一起出现
                    exclusion_strength = 1.0
                    exclusion_type = "强互斥"
                    strong_exclusions.append({
                        'ball1': ball1,
                        'ball2': ball2,
                        'ball1_count': ball1_count,
                        'ball2_count': ball2_count,
                        'co_occurrence': co_count,
                        'expected_co': round(expected_co, 2),
                        'exclusion_strength': exclusion_strength
                    })
                elif co_count < expected_co * 0.5:
                    # 很少一起出现（少于期望值的一半）
                    exclusion_strength = 1 - (co_count / expected_co)
                    exclusion_type = "弱互斥"
                    weak_exclusions.append({
                        'ball1': ball1,
                        'ball2': ball2,
                        'ball1_count': ball1_count,
                        'ball2_count': ball2_count,
                        'co_occurrence': co_count,
                        'expected_co': round(expected_co, 2),
                        'exclusion_strength': round(exclusion_strength, 3)
                    })
                
                exclusion_relationships.append({
                    'ball1': ball1,
                    'ball2': ball2,
                    'ball1_count': ball1_count,
                    'ball2_count': ball2_count,
                    'co_occurrence': co_count,
                    'expected_co': round(expected_co, 2),
                    'exclusion_strength': round(1 - (co_count / expected_co) if expected_co > 0 else 0, 3)
                })
            
            # 按互斥强度排序
            strong_exclusions.sort(key=lambda x: x['exclusion_strength'], reverse=True)
            weak_exclusions.sort(key=lambda x: x['exclusion_strength'], reverse=True)
            
            # 生成分析报告
            analysis_report = f"""双色球红球互斥关系分析报告

分析期数：{total_draws}期
分析时间范围：{lottery_data[-1].draw_date.strftime('%Y-%m-%d')} 至 {lottery_data[0].draw_date.strftime('%Y-%m-%d')}

📊 强互斥关系（从未一起出现）：
"""
            
            for i, exclusion in enumerate(strong_exclusions[:10], 1):
                analysis_report += f"{i}. 红球{exclusion['ball1']:02d} 与 红球{exclusion['ball2']:02d}\n"
                analysis_report += f"   红球{exclusion['ball1']:02d}出现{exclusion['ball1_count']}次，红球{exclusion['ball2']:02d}出现{exclusion['ball2_count']}次\n"
                analysis_report += f"   期望共现{exclusion['expected_co']}次，实际共现{exclusion['co_occurrence']}次\n\n"
            
            if weak_exclusions:
                analysis_report += "📈 弱互斥关系（很少一起出现）：\n"
                for i, exclusion in enumerate(weak_exclusions[:10], 1):
                    analysis_report += f"{i}. 红球{exclusion['ball1']:02d} 与 红球{exclusion['ball2']:02d}（互斥强度：{exclusion['exclusion_strength']}）\n"
                    analysis_report += f"   红球{exclusion['ball1']:02d}出现{exclusion['ball1_count']}次，红球{exclusion['ball2']:02d}出现{exclusion['ball2_count']}次\n"
                    analysis_report += f"   期望共现{exclusion['expected_co']}次，实际共现{exclusion['co_occurrence']}次\n\n"
            
            # 添加使用建议
            analysis_report += """💡 使用建议：
1. 强互斥的号码对在选号时可以避免同时选择
2. 弱互斥的号码对可以谨慎选择，但不必完全避免
3. 互斥关系可能随时间变化，建议定期更新分析
4. 互斥分析仅供参考，不能保证预测准确性

🔍 统计说明：
- 互斥强度：0-1之间，越接近1表示互斥性越强
- 期望共现：基于独立假设计算的期望共现次数
- 实际共现：历史数据中实际一起出现的次数
"""
            
            return {
                'total_draws': total_draws,
                'date_range': {
                    'start_date': lottery_data[-1].draw_date.isoformat(),
                    'end_date': lottery_data[0].draw_date.isoformat()
                },
                'strong_exclusions': strong_exclusions,
                'weak_exclusions': weak_exclusions,
                'all_relationships': exclusion_relationships,
                'analysis_report': analysis_report
            }
            
        except Exception as e:
            print(f"互斥分析失败: {e}")
            raise
    
    def analyze_lottery_data(lottery_data):
        """分析彩票数据，应用杀号和选号规则"""
        if not lottery_data:
            return [], "无历史数据"
        
        # 转换为分析格式
        history_data = []
        for item in lottery_data:
            history_data.append({
                'draw_number': item.draw_number,
                'draw_date': item.draw_date.isoformat(),
                'red_balls': [item.red_ball_1, item.red_ball_2, item.red_ball_3, 
                             item.red_ball_4, item.red_ball_5, item.red_ball_6],
                'blue_ball': item.blue_ball
            })
        
        # 红球杀号规则
        red_kill_numbers = apply_red_ball_kill_rules(history_data)
        
        # 蓝球杀号规则
        blue_kill_numbers = apply_blue_ball_kill_rules(history_data)
        
        # 红球选号规则
        red_select_numbers = apply_red_ball_select_rules(history_data, red_kill_numbers)
        
        # 蓝球选号规则
        blue_select_numbers = apply_blue_ball_select_rules(history_data, blue_kill_numbers)
        
        return {
            'red_kill': red_kill_numbers,
            'blue_kill': blue_kill_numbers,
            'red_select': red_select_numbers,
            'blue_select': blue_select_numbers,
            'history_data': history_data
        }
    
    def apply_red_ball_kill_rules(history_data):
        """应用红球杀号规则"""
        kill_numbers = set()
        
        if len(history_data) < 5:
            return list(kill_numbers)
        
        # 统计每个红球的出现次数
        red_counts = {}
        for i in range(1, 34):
            red_counts[i] = 0
        
        # 统计最近20期的红球出现情况
        recent_data = history_data[-20:] if len(history_data) >= 20 else history_data
        
        for draw in recent_data:
            for ball in draw['red_balls']:
                red_counts[ball] += 1
        
        # 杀号规则1：长期未出现的号码
        for ball, count in red_counts.items():
            if count == 0 and len(recent_data) >= 20:
                kill_numbers.add(ball)
        
        # 杀号规则2：高频号码
        for ball, count in red_counts.items():
            if count >= 13:  # 近20期出现13次以上
                kill_numbers.add(ball)
        
        # 杀号规则3：近期过热号码
        recent_5_data = history_data[-5:] if len(history_data) >= 5 else history_data
        recent_5_counts = {}
        for i in range(1, 34):
            recent_5_counts[i] = 0
        
        for draw in recent_5_data:
            for ball in draw['red_balls']:
                recent_5_counts[ball] += 1
        
        for ball, count in recent_5_counts.items():
            if count >= 3:  # 近5期出现3次以上
                kill_numbers.add(ball)
        
        return list(kill_numbers)
    
    def apply_blue_ball_kill_rules(history_data):
        """应用蓝球杀号规则"""
        kill_numbers = set()
        
        if len(history_data) < 5:
            return list(kill_numbers)
        
        # 统计每个蓝球的出现次数
        blue_counts = {}
        for i in range(1, 17):
            blue_counts[i] = 0
        
        # 统计最近20期的蓝球出现情况
        recent_data = history_data[-20:] if len(history_data) >= 20 else history_data
        
        for draw in recent_data:
            blue_counts[draw['blue_ball']] += 1
        
        # 杀号规则1：长期未出现的号码
        for ball, count in blue_counts.items():
            if count == 0 and len(recent_data) >= 20:
                kill_numbers.add(ball)
        
        # 杀号规则2：高频号码
        for ball, count in blue_counts.items():
            if count >= 8:  # 近20期出现8次以上
                kill_numbers.add(ball)
        
        return list(kill_numbers)
    
    def apply_red_ball_select_rules(history_data, kill_numbers):
        """应用红球选号规则"""
        available_numbers = [i for i in range(1, 34) if i not in kill_numbers]
        
        if len(available_numbers) < 6:
            # 如果可用号码不足，从所有号码中选择
            available_numbers = list(range(1, 34))
        
        # 选号规则：平衡分布
        selected = []
        for _ in range(5):  # 生成5组
            group = random.sample(available_numbers, 6)
            group.sort()
            selected.append(group)
        
        return selected
    
    def apply_blue_ball_select_rules(history_data, kill_numbers):
        """应用蓝球选号规则"""
        available_numbers = [i for i in range(1, 17) if i not in kill_numbers]
        
        if len(available_numbers) < 1:
            available_numbers = list(range(1, 17))
        
        # 选号规则：随机选择
        selected = []
        for _ in range(5):  # 生成5组
            selected.append(random.choice(available_numbers))
        
        return selected
    
    def call_deepseek_ai(lottery_data, custom_prompt="", exclusion_analysis=None):
        """调用DeepSeek AI进行分析"""
        try:
            # 添加调试日志
            print(f"[DEBUG] call_deepseek_ai接收到的custom_prompt: '{custom_prompt}'")
            print(f"[DEBUG] 互斥分析数据: {exclusion_analysis is not None}")
            
            # 构建分析数据
            analysis_result = analyze_lottery_data(lottery_data)
            
            # 构建AI提示，传递自定义提示词和互斥关系
            prompt = build_ai_prompt(analysis_result, custom_prompt, exclusion_analysis)
            
            # 调用DeepSeek API
            response = call_deepseek_api(prompt)
            
            # 解析AI响应
            predictions, analysis = parse_ai_response(response)
            
            # 返回更多信息用于记录
            return {
                'predictions': predictions,
                'analysis': analysis,
                'prompt': prompt,
                'ai_response': response,
                'ai_model': 'deepseek-chat',
                'analysis_process': f"基于{len(lottery_data)}期历史数据，使用DeepSeek AI进行分析"
            }
            
        except Exception as e:
            print(f"DeepSeek AI调用失败: {e}")
            # 使用本地规则作为备选
            fallback_result = fallback_prediction(lottery_data, exclusion_analysis)
            return {
                'predictions': fallback_result['predictions'],
                'analysis': fallback_result['analysis'],
                'prompt': f"备选方案：基于{len(lottery_data)}期历史数据",
                'ai_response': '使用备选预测方案',
                'ai_model': 'fallback',
                'analysis_process': f"AI调用失败，使用备选方案生成预测"
            }
    
    def build_ai_prompt(analysis_result, custom_prompt="", exclusion_analysis=None):
        """构建AI提示"""
        # 添加调试日志
        print(f"[DEBUG] build_ai_prompt接收到的custom_prompt: '{custom_prompt}'")
        print(f"[DEBUG] 互斥分析数据: {exclusion_analysis is not None}")
        
        # 根据是否有自定义提示词来构建不同的提示
        if custom_prompt:
            analysis_instruction = custom_prompt
        else:
            analysis_instruction = "分析红球的杀号规律和选号规律，特别注意互斥关系"
        
        # 获取最后一期中奖号码信息
        history_data = analysis_result['history_data']
        
        # 检查history_data的类型并处理
        if isinstance(history_data, list):
            # 如果是列表，使用最后一个元素
            if len(history_data) >= 1:
                latest_draw = history_data[-1]
                draw_info = latest_draw.get('draw_number', '')
                red_balls = latest_draw.get('red_balls', [])
                blue_ball = latest_draw.get('blue_ball', 0)
                
                # 格式化红球号码
                red_balls_str = ' '.join([f"{ball:02d}" for ball in red_balls])
                blue_ball_str = f"{blue_ball:02d}"
                
                latest_draw_info = f"最新期号: {draw_info}\n最新中奖号码: 红球: {red_balls_str} 蓝球: {blue_ball_str}"
            else:
                latest_draw_info = "最新中奖号码: 暂无数据"
        elif isinstance(history_data, str):
            # 如果是字符串，按行分割
            history_lines = history_data.split('\n')
            if len(history_lines) >= 1:
                latest_draw_line = history_lines[-1]
                if ':' in latest_draw_line:
                    draw_info = latest_draw_line.split(':')[0]
                    numbers_info = latest_draw_line.split(':')[1] if ':' in latest_draw_line else ''
                    latest_draw_info = f"最新期号: {draw_info}\n最新中奖号码: {numbers_info}"
                else:
                    latest_draw_info = f"最新中奖号码: {latest_draw_line}"
            else:
                latest_draw_info = "最新中奖号码: 暂无数据"
        else:
            latest_draw_info = "最新中奖号码: 暂无数据"
        
        # 将历史数据转换为字符串格式
        history_data = analysis_result['history_data']
        if isinstance(history_data, list):
            history_lines = []
            for draw in history_data:
                draw_number = draw.get('draw_number', '')
                draw_date = draw.get('draw_date', '')
                red_balls = draw.get('red_balls', [])
                blue_ball = draw.get('blue_ball', 0)
                
                # 格式化红球号码
                red_balls_str = ' '.join([f"{ball:02d}" for ball in red_balls])
                blue_ball_str = f"{blue_ball:02d}"
                
                history_lines.append(f"{draw_number}: {draw_date} - 红球: {red_balls_str} 蓝球: {blue_ball_str}")
            
            history_data_str = '\n'.join(history_lines)
        else:
            history_data_str = str(history_data)
        
        # 构建互斥关系信息
        exclusion_info = ""
        if exclusion_analysis:
            strong_exclusions = exclusion_analysis.get('strong_exclusions', [])
            weak_exclusions = exclusion_analysis.get('weak_exclusions', [])
            
            if strong_exclusions or weak_exclusions:
                exclusion_info = "\n⚠️ 重要：互斥关系分析（必须严格遵守）：\n"
                
                if strong_exclusions:
                    exclusion_info += "🚫 强互斥关系（绝对禁止同时选择）：\n"
                    for i, exclusion in enumerate(strong_exclusions, 1):  # 显示全部强互斥关系
                        exclusion_info += f"  {i}. 红球{exclusion['ball1']:02d} 与 红球{exclusion['ball2']:02d}（从未一起出现）\n"
                
                if weak_exclusions:
                    exclusion_info += "⚠️ 弱互斥关系（建议避免同时选择）：\n"
                    for i, exclusion in enumerate(weak_exclusions, 1):  # 显示全部弱互斥关系
                        exclusion_info += f"  {i}. 红球{exclusion['ball1']:02d} 与 红球{exclusion['ball2']:02d}（互斥强度：{exclusion['exclusion_strength']:.3f}）\n"
                
                exclusion_info += "\n🔴 选号规则：\n"
                exclusion_info += "1. 绝对禁止在同一组预测中同时选择强互斥的号码对\n"
                exclusion_info += "2. 尽量避免在同一组预测中同时选择弱互斥的号码对\n"
                exclusion_info += "3. 如果必须选择弱互斥号码，最多只能选择一对\n"
                exclusion_info += "4. 生成预测号码前，必须检查是否违反互斥规则\n\n"

        prompt = f"""
请基于以下双色球历史数据分析，生成5组预测号码：

历史中奖数据分析：
- 中奖数据信息：{history_data_str}

{latest_draw_info}

{exclusion_info}

{analysis_instruction}

"""
        return prompt
    
    def call_deepseek_api(prompt):
        """调用DeepSeek API"""
        try:
            # 这里应该使用真实的DeepSeek API密钥
            # 为了演示，我们使用模拟响应
            api_key = "sk-d8b48b0fcd5e4ee7823d7ce71db41fde"  # 需要替换为真实的API密钥
            
            headers = {
                "Authorization": f"Bearer {api_key}",
                "Content-Type": "application/json"
            }
            
            data = {
                "model": "deepseek-chat",
                "messages": [
                    {"role": "user", "content": prompt}
                ],
                "temperature": 0.7,
                "max_tokens": 1000
            }
            
            # 设置更长的超时时间
            timeout = 90  # 90秒超时
            
            print(f"[DEBUG] 开始调用DeepSeek API，超时时间: {timeout}秒")
            
            # 模拟API调用（实际使用时取消注释下面的代码）
            response = requests.post("https://api.deepseek.com/v1/chat/completions",
                                    headers=headers, json=data, timeout=timeout)
            
            print(f"[DEBUG] DeepSeek API响应状态: {response.status_code}")
            return response.json()
            
            # 模拟响应
#             return {
#                 "choices": [{
#                     "message": {
#                         "content": """
# 预测号码：
# 第1组:红球[2,4,12,16,22,28],蓝球04
# 第2组:红球[5,11,16,20,25,33],蓝球08
# 第3组:红球[7,13,17,21,26,30],蓝球10
# 第4组:红球[3,9,15,19,24,31],蓝球12
# 第5组:红球[1,8,14,18,23,29],蓝球16
#
# 分析说明：
# 1. 应用了多种杀号规则，包括长期未出、高频号码、区间过热等
# 2. 考虑了号码的冷热分布和奇偶平衡
# 3. 避免了极端值的延续
# 4. 推荐以上5组号码组合
# """
#                     }
#                 }]
#             }
            
        except requests.exceptions.Timeout:
            print(f"DeepSeek API调用超时")
            raise Exception("AI分析超时，请稍后重试")
        except requests.exceptions.RequestException as e:
            print(f"DeepSeek API网络错误: {e}")
            raise Exception(f"AI服务网络错误: {str(e)}")
        except Exception as e:
            print(f"DeepSeek API调用失败: {e}")
            raise e
    
    def parse_ai_response(response):
        """解析AI响应"""
        try:
            content = response['choices'][0]['message']['content']
            print(f"[DEBUG] AI响应内容: {content}")
            
            # 解析预测号码
            predictions = []
            lines = content.split('\n')
            
            for line in lines:
                line = line.strip()
                print(f"[DEBUG] 解析行: {line}")
                
                # 尝试多种格式匹配
                if '第' in line and ('组:' in line or '组：' in line):
                    print(f"[DEBUG] 找到组行: {line}")
                    
                    # 解析红球 - 尝试多种格式
                    red_balls = []
                    
                    # 格式1: 红球[1,2,3,4,5,6]
                    red_match = re.search(r'红球\[([^\]]+)\]', line)
                    if red_match:
                        try:
                            red_balls = [int(x.strip()) for x in red_match.group(1).split(',') if x.strip().isdigit()]
                            print(f"[DEBUG] 格式1匹配成功: {red_balls}")
                        except Exception as e:
                            print(f"[DEBUG] 格式1解析失败: {e}")
                    
                    # 格式2: 红球 1 2 3 4 5 6
                    if not red_balls:
                        red_match = re.search(r'红球\s*(\d+)\s*(\d+)\s*(\d+)\s*(\d+)\s*(\d+)\s*(\d+)', line)
                        if red_match:
                            try:
                                red_balls = [int(red_match.group(i)) for i in range(1, 7)]
                                print(f"[DEBUG] 格式2匹配成功: {red_balls}")
                            except Exception as e:
                                print(f"[DEBUG] 格式2解析失败: {e}")
                    
                    # 格式3: 红球: 1,2,3,4,5,6
                    if not red_balls:
                        red_match = re.search(r'红球[:：]\s*([\d,\s]+)', line)
                        if red_match:
                            try:
                                red_balls = [int(x.strip()) for x in red_match.group(1).split(',') if x.strip().isdigit()]
                                print(f"[DEBUG] 格式3匹配成功: {red_balls}")
                            except Exception as e:
                                print(f"[DEBUG] 格式3解析失败: {e}")
                    
                    # 格式4: 直接匹配数字序列 [1,2,3,4,5,6]
                    if not red_balls:
                        red_match = re.search(r'\[(\d+,\d+,\d+,\d+,\d+,\d+)\]', line)
                        if red_match:
                            try:
                                red_balls = [int(x.strip()) for x in red_match.group(1).split(',')]
                                print(f"[DEBUG] 格式4匹配成功: {red_balls}")
                            except Exception as e:
                                print(f"[DEBUG] 格式4解析失败: {e}")
                    
                    # 解析蓝球 - 尝试多种格式
                    blue_ball = None
                    
                    # 格式1: 蓝球04
                    blue_match = re.search(r'蓝球(\d+)', line)
                    if blue_match:
                        try:
                            blue_ball = int(blue_match.group(1))
                            print(f"[DEBUG] 蓝球格式1匹配成功: {blue_ball}")
                        except Exception as e:
                            print(f"[DEBUG] 蓝球格式1解析失败: {e}")
                    
                    # 格式2: 蓝球: 04
                    if not blue_ball:
                        blue_match = re.search(r'蓝球[:：]\s*(\d+)', line)
                        if blue_match:
                            try:
                                blue_ball = int(blue_match.group(1))
                                print(f"[DEBUG] 蓝球格式2匹配成功: {blue_ball}")
                            except Exception as e:
                                print(f"[DEBUG] 蓝球格式2解析失败: {e}")
                    
                    # 格式3: 直接匹配蓝球数字
                    if not blue_ball:
                        blue_match = re.search(r',蓝球(\d+)', line)
                        if blue_match:
                            try:
                                blue_ball = int(blue_match.group(1))
                                print(f"[DEBUG] 蓝球格式3匹配成功: {blue_ball}")
                            except Exception as e:
                                print(f"[DEBUG] 蓝球格式3解析失败: {e}")
                    
                    # 验证红球和蓝球的有效性
                    if red_balls and len(red_balls) == 6:
                        # 检查红球范围 (1-33)
                        valid_reds = all(1 <= ball <= 33 for ball in red_balls)
                        # 检查红球是否有重复
                        unique_reds = len(set(red_balls)) == 6
                        
                        if valid_reds and unique_reds and blue_ball and 1 <= blue_ball <= 16:
                            predictions.append({
                                'red_balls': sorted(red_balls),  # 确保红球排序
                                'blue_ball': blue_ball
                            })
                            print(f"[DEBUG] 添加预测: 红球{sorted(red_balls)}, 蓝球{blue_ball}")
                        else:
                            print(f"[DEBUG] 验证失败: 红球{red_balls}(有效:{valid_reds},唯一:{unique_reds}), 蓝球{blue_ball}")
                    else:
                        print(f"[DEBUG] 红球解析失败: {red_balls}")
            
            print(f"[DEBUG] 最终预测数量: {len(predictions)}")
            
            # 如果没有解析到任何预测，使用备选方案
            if not predictions:
                print("[DEBUG] 未解析到预测数据，使用备选方案")
                fallback_result = fallback_prediction([], None)
                return fallback_result['predictions'], fallback_result['analysis']
            
            # 解析分析说明
            analysis = ""
            for line in lines:
                if '分析说明：' in line or line.strip().startswith(('1.', '2.', '3.', '4.')):
                    analysis += line + '\n'
            
            return predictions, content
        except Exception as e:
            print(f"解析AI响应失败: {e}")
            import traceback
            traceback.print_exc()
            fallback_result = fallback_prediction([], None)
            return fallback_result['predictions'], fallback_result['analysis']
    
    def fallback_prediction(lottery_data, exclusion_analysis=None):
        """备选预测方案"""
        import random
        predictions = []
        
        # 如果有互斥关系数据，避免选择强互斥的号码对
        excluded_pairs = set()
        weak_excluded_pairs = set()
        if exclusion_analysis:
            strong_exclusions = exclusion_analysis.get('strong_exclusions', [])
            weak_exclusions = exclusion_analysis.get('weak_exclusions', [])
            
            for exclusion in strong_exclusions:
                excluded_pairs.add((exclusion['ball1'], exclusion['ball2']))
                excluded_pairs.add((exclusion['ball2'], exclusion['ball1']))
            
            for exclusion in weak_exclusions:
                weak_excluded_pairs.add((exclusion['ball1'], exclusion['ball2']))
                weak_excluded_pairs.add((exclusion['ball2'], exclusion['ball1']))
        
        for i in range(5):
            attempts = 0
            max_attempts = 200  # 增加尝试次数
            
            while attempts < max_attempts:
                red_balls = sorted(random.sample(range(1, 34), 6))
                
                # 检查是否包含强互斥的号码对
                has_strong_exclusion = False
                weak_exclusion_count = 0
                
                if excluded_pairs or weak_excluded_pairs:
                    for j in range(len(red_balls)):
                        for k in range(j + 1, len(red_balls)):
                            pair = (red_balls[j], red_balls[k])
                            if pair in excluded_pairs:
                                has_strong_exclusion = True
                                break
                            elif pair in weak_excluded_pairs:
                                weak_exclusion_count += 1
                        if has_strong_exclusion:
                            break
                
                # 如果没有强互斥且弱互斥不超过1对，则接受这组号码
                if not has_strong_exclusion and weak_exclusion_count <= 1:
                    # 额外检查：确保没有07和12同时出现
                    if not (7 in red_balls and 12 in red_balls):
                        break
                
                attempts += 1
            
            blue_ball = random.randint(1, 16)
            predictions.append({
                'red_balls': red_balls,
                'blue_ball': blue_ball
            })
        
        analysis = f"基于{len(lottery_data)}期历史数据分析，生成了5组预测号码"
        if exclusion_analysis:
            strong_count = len(excluded_pairs) // 2
            weak_count = len(weak_excluded_pairs) // 2
            analysis += f"，严格遵守了{strong_count}个强互斥关系，考虑了{weak_count}个弱互斥关系"
            analysis += "。每组预测都经过互斥关系验证，确保不违反强互斥规则。"
        
        print(f"[DEBUG] 备选预测方案生成: {predictions}")
        return {
            'predictions': predictions,
            'analysis': analysis,
            'prompt': f"备选方案：基于{len(lottery_data)}期历史数据",
            'ai_response': '使用备选预测方案',
            'ai_model': 'fallback',
            'analysis_process': f"AI调用失败，使用备选方案生成预测"
        }
    
    def fetch_lottery_data_from_api():
        """从API获取双色球数据"""
        try:
            print("正在从API获取双色球数据...")
            
            # 使用中彩网API
            base_url = "http://kaijiang.zhcw.com/zhcw/html/ssq/list_1.html"
            headers = {
                'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36'
            }
            
            # 获取网页内容
            response = requests.get(base_url, headers=headers, timeout=10)
            response.raise_for_status()
            response.encoding = 'utf-8'
            
            # 解析HTML
            soup = BeautifulSoup(response.text, 'html.parser')
            
            # 查找开奖数据表格
            table = soup.find('table', class_='table-common')
            if not table:
                raise Exception("未找到开奖数据表格")
            
            rows = table.find_all('tr')[1:]  # 跳过表头
            api_data = []
            
            for row in rows:
                try:
                    cells = row.find_all('td')
                    if len(cells) < 8:
                        continue
                    
                    # 解析开奖日期
                    date_text = cells[0].get_text(strip=True)
                    draw_date = datetime.strptime(date_text, '%Y-%m-%d').date()
                    
                    # 解析期数
                    draw_number = cells[1].get_text(strip=True)
                    
                    # 解析红球和蓝球
                    numbers_text = cells[2].get_text(strip=True)
                    numbers = re.findall(r'\d+', numbers_text)
                    
                    if len(numbers) != 7:
                        continue
                    
                    red_balls = [int(num) for num in numbers[:6]]
                    blue_ball = int(numbers[6])
                    
                    # 验证号码范围
                    if not all(1 <= ball <= 33 for ball in red_balls):
                        continue
                    if not 1 <= blue_ball <= 16:
                        continue
                    
                    # 获取奖金信息
                    prize_info = cells[3].get_text(strip=True) if len(cells) > 3 else ''
                    
                    api_data.append({
                        'draw_date': draw_date.strftime('%Y-%m-%d'),
                        'draw_number': draw_number,
                        'red_balls': red_balls,
                        'blue_ball': blue_ball,
                        'prize_info': prize_info
                    })
                    
                except Exception as e:
                    print(f"解析行数据失败: {str(e)}")
                    continue
            
            print(f"从API获取到 {len(api_data)} 条数据")
            return api_data
            
        except Exception as e:
            print(f"从API获取数据失败: {e}")
            # 如果API获取失败，返回一些模拟数据作为备选
            print("使用备选数据...")
            return [
                {
                    'draw_date': '2024-12-31',
                    'draw_number': '2024150',
                    'red_balls': [1, 5, 10, 19, 26, 28],
                    'blue_ball': 12,
                    'prize_info': '一等奖1注'
                },
                {
                    'draw_date': '2024-12-29',
                    'draw_number': '2024149',
                    'red_balls': [3, 7, 12, 18, 25, 31],
                    'blue_ball': 8,
                    'prize_info': '一等奖2注'
                }
            ]
    
    # 数据模型
    class User(db.Model):
        __tablename__ = 'users'
        id = db.Column(db.Integer, primary_key=True)
        username = db.Column(db.String(80), unique=True, nullable=False)
        password_hash = db.Column(db.String(120), nullable=False)
        created_at = db.Column(db.DateTime, default=db.func.current_timestamp())
        updated_at = db.Column(db.DateTime, default=db.func.current_timestamp(), onupdate=db.func.current_timestamp())
        
        def set_password(self, password):
            self.password_hash = generate_password_hash(password)
        
        def check_password(self, password):
            return check_password_hash(self.password_hash, password)

    # def get_ai_prediction_model():
    #     from backend.models.ai_prediction import AIPrediction
    #     return AIPrediction
    class LotteryResult(db.Model):
        __tablename__ = 'lottery_results'
        id = db.Column(db.Integer, primary_key=True)
        draw_date = db.Column(db.Date, nullable=False)
        draw_number = db.Column(db.String(20), unique=True, nullable=False)
        red_ball_1 = db.Column(db.Integer, nullable=False)
        red_ball_2 = db.Column(db.Integer, nullable=False)
        red_ball_3 = db.Column(db.Integer, nullable=False)
        red_ball_4 = db.Column(db.Integer, nullable=False)
        red_ball_5 = db.Column(db.Integer, nullable=False)
        red_ball_6 = db.Column(db.Integer, nullable=False)
        blue_ball = db.Column(db.Integer, nullable=False)
        prize_info = db.Column(db.Text)
        created_at = db.Column(db.DateTime, default=db.func.current_timestamp())
    
    class AIPrediction(db.Model):
        __tablename__ = 'ai_predictions'
        id = db.Column(db.Integer, primary_key=True)
        start_draw = db.Column(db.String(20), nullable=False)
        end_draw = db.Column(db.String(20), nullable=False)
        data_count = db.Column(db.Integer, nullable=False)
        predicted_numbers = db.Column(db.Text, nullable=False)
        actual_result = db.Column(db.Text)
        win_info = db.Column(db.Text)
        win_amount = db.Column(db.Numeric(10, 2), default=0)
        analysis_result = db.Column(db.Text)
        created_at = db.Column(db.DateTime, default=db.func.current_timestamp())
    
    class SystemConfig(db.Model):
        __tablename__ = 'system_config'
        id = db.Column(db.Integer, primary_key=True)
        key = db.Column(db.String(100), unique=True, nullable=False)
        value = db.Column(db.Text)
        description = db.Column(db.String(200))
        created_at = db.Column(db.DateTime, default=db.func.current_timestamp())
        updated_at = db.Column(db.DateTime, default=db.func.current_timestamp(), onupdate=db.func.current_timestamp())
    
    # 蓝图
    auth_bp = Blueprint('auth', __name__)
    lottery_bp = Blueprint('lottery', __name__)
    ai_bp = Blueprint('ai', __name__)
    reports_bp = Blueprint('reports', __name__)
    
    # 认证路由
    @auth_bp.route('/login', methods=['POST'])
    def login():
        try:
            data = request.get_json()
            if not data:
                return jsonify({'error': '请求数据为空'}), 400
            
            username = data.get('username')
            password = data.get('password')
            
            if not username or not password:
                return jsonify({'error': '用户名和密码不能为空'}), 400
            
            print(f"登录尝试: 用户名={username}")
            
            user = User.query.filter_by(username=username).first()
            if user:
                print(f"✓ 用户存在: {username}")
                if user.check_password(password):
                    print(f"✓ 密码验证成功")
                    access_token = create_access_token(identity=str(user.id))
                    return jsonify({
                        'access_token': access_token,
                        'user': {
                            'id': user.id,
                            'username': user.username
                        }
                    }), 200
                else:
                    print(f"✗ 密码验证失败")
                    return jsonify({'error': '用户名或密码错误'}), 401
            else:
                print(f"✗ 用户不存在: {username}")
                return jsonify({'error': '用户名或密码错误'}), 401
                
        except Exception as e:
            print(f"登录错误: {e}")
            return jsonify({'error': f'登录失败: {str(e)}'}), 500
    
    @auth_bp.route('/profile', methods=['GET'])
    @jwt_required()
    def get_profile():
        try:
            user_id = get_jwt_identity()
            print(f"获取用户信息，用户ID: {user_id}")
            
            user_id_int = int(user_id) if user_id else None
            user = User.query.get(user_id_int)
            
            if user:
                return jsonify({
                    'id': user.id,
                    'username': user.username,
                    'created_at': user.created_at.isoformat() if user.created_at else None
                }), 200
            else:
                return jsonify({'error': '用户不存在'}), 404
                
        except Exception as e:
            print(f"获取用户信息错误: {e}")
            return jsonify({'error': f'获取用户信息失败: {str(e)}'}), 500
    
    @auth_bp.route('/init', methods=['POST'])
    def init_admin():
        try:
            admin = User.query.filter_by(username='admin').first()
            if admin:
                admin.set_password('admin123')
                db.session.commit()
                print(f"✓ 管理员账户已存在，密码已重置为: admin123")
                return jsonify({'message': '管理员账户已存在，密码已重置'}), 200
            
            admin = User(username='admin')
            admin.set_password('admin123')
            db.session.add(admin)
            db.session.commit()
            
            print(f"✓ 管理员账户创建成功，密码: admin123")
            return jsonify({'message': '管理员账户创建成功'}), 201
            
        except Exception as e:
            db.session.rollback()
            print(f"✗ 管理员初始化失败: {e}")
            return jsonify({'error': f'初始化失败: {str(e)}'}), 500
    
    # 彩票数据路由
    @lottery_bp.route('/list', methods=['GET'])
    @jwt_required()
    def get_lottery_list():
        try:
            page = request.args.get('page', 1, type=int)
            per_page = request.args.get('per_page', 20, type=int)
            start_date = request.args.get('start_date')
            end_date = request.args.get('end_date')
            draw_number = request.args.get('draw_number')
            red_ball_1 = request.args.get('red_ball_1', type=int)
            red_ball_2 = request.args.get('red_ball_2', type=int)
            red_ball_3 = request.args.get('red_ball_3', type=int)
            red_ball_4 = request.args.get('red_ball_4', type=int)
            red_ball_5 = request.args.get('red_ball_5', type=int)
            red_ball_6 = request.args.get('red_ball_6', type=int)
            blue_ball = request.args.get('blue_ball', type=int)
            
            query = LotteryResult.query
            
            if start_date:
                query = query.filter(LotteryResult.draw_date >= start_date)
            if end_date:
                query = query.filter(LotteryResult.draw_date <= end_date)
            if draw_number:
                query = query.filter(LotteryResult.draw_number.like(f'%{draw_number}%'))
            if red_ball_1:
                query = query.filter(LotteryResult.red_ball_1 == red_ball_1)
            if red_ball_2:
                query = query.filter(LotteryResult.red_ball_2 == red_ball_2)
            if red_ball_3:
                query = query.filter(LotteryResult.red_ball_3 == red_ball_3)
            if red_ball_4:
                query = query.filter(LotteryResult.red_ball_4 == red_ball_4)
            if red_ball_5:
                query = query.filter(LotteryResult.red_ball_5 == red_ball_5)
            if red_ball_6:
                query = query.filter(LotteryResult.red_ball_6 == red_ball_6)
            if blue_ball:
                query = query.filter(LotteryResult.blue_ball == blue_ball)
            
            pagination = query.order_by(LotteryResult.draw_date.desc()).paginate(
                page=page, per_page=per_page, error_out=False
            )
            
            result_data = []
            for item in pagination.items:
                result_data.append({
                    'id': item.id,
                    'draw_date': item.draw_date.isoformat(),
                    'draw_number': item.draw_number,
                    'red_ball_1': item.red_ball_1,
                    'red_ball_2': item.red_ball_2,
                    'red_ball_3': item.red_ball_3,
                    'red_ball_4': item.red_ball_4,
                    'red_ball_5': item.red_ball_5,
                    'red_ball_6': item.red_ball_6,
                    'blue_ball': item.blue_ball,
                    'prize_info': item.prize_info,
                    'created_at': item.created_at.isoformat() if item.created_at else None
                })
            
            return jsonify({
                'data': result_data,
                'total': pagination.total,
                'pages': pagination.pages,
                'current_page': page
            }), 200
            
        except Exception as e:
            print(f"获取彩票数据失败: {e}")
            return jsonify({'error': f'获取数据失败: {str(e)}'}), 500
    
    @lottery_bp.route('/statistics', methods=['GET'])
    @jwt_required()
    def get_statistics():
        try:
            total_count = LotteryResult.query.count()
            
            # 最近一期的数据
            latest_draw = LotteryResult.query.order_by(LotteryResult.draw_date.desc()).first()
            
            # 红球统计
            red_stats = {}
            for i in range(1, 34):
                red_stats[i] = 0
            
            # 蓝球统计
            blue_stats = {}
            for i in range(1, 17):
                blue_stats[i] = 0
            
            # 统计最近100期
            recent_draws = LotteryResult.query.order_by(LotteryResult.draw_date.desc()).limit(100).all()
            
            for draw in recent_draws:
                red_stats[draw.red_ball_1] += 1
                red_stats[draw.red_ball_2] += 1
                red_stats[draw.red_ball_3] += 1
                red_stats[draw.red_ball_4] += 1
                red_stats[draw.red_ball_5] += 1
                red_stats[draw.red_ball_6] += 1
                blue_stats[draw.blue_ball] += 1
            
            # 获取期数范围
            min_draw = LotteryResult.query.order_by(LotteryResult.draw_number.asc()).first()
            max_draw = LotteryResult.query.order_by(LotteryResult.draw_number.desc()).first()
            
            return jsonify({
                'total_lottery_data': total_count,
                'latest_draw': {
                    'draw_number': latest_draw.draw_number,
                    'draw_date': latest_draw.draw_date.isoformat(),
                    'red_balls': [latest_draw.red_ball_1, latest_draw.red_ball_2, latest_draw.red_ball_3,
                                 latest_draw.red_ball_4, latest_draw.red_ball_5, latest_draw.red_ball_6],
                    'blue_ball': latest_draw.blue_ball
                } if latest_draw else None,
                'red_stats': red_stats,
                'blue_stats': blue_stats,
                'draw_range': {
                    'min_draw': min_draw.draw_number if min_draw else None,
                    'max_draw': max_draw.draw_number if max_draw else None
                }
            }), 200
            
        except Exception as e:
            print(f"获取统计数据失败: {e}")
            return jsonify({'error': f'获取统计失败: {str(e)}'}), 500
    
    @lottery_bp.route('/range', methods=['GET'])
    @jwt_required()
    def get_draw_range():
        """获取期数范围"""
        try:
            min_draw = LotteryResult.query.order_by(LotteryResult.draw_number.asc()).first()
            max_draw = LotteryResult.query.order_by(LotteryResult.draw_number.desc()).first()
            
            return jsonify({
                'min_draw': min_draw.draw_number if min_draw else None,
                'max_draw': max_draw.draw_number if max_draw else None,
                'total_count': LotteryResult.query.count()
            }), 200
            
        except Exception as e:
            print(f"获取期数范围失败: {e}")
            return jsonify({'error': f'获取期数范围失败: {str(e)}'}), 500
    
    @lottery_bp.route('/update', methods=['POST'])
    # @jwt_required()  # 临时注释掉JWT认证
    def update_data():
        try:
            print("开始从API更新双色球数据...")
            
            # 使用新的爬取服务
            from backend.services.lottery_crawler import LotteryCrawler
            crawler = LotteryCrawler()
            
            # 获取请求参数
            data = request.get_json() or {}
            target_count = data.get('target_count', 30)  # 默认30期
            max_pages = data.get('max_pages', 3)  # 默认3页
            
            # 执行爬取
            result = crawler.crawl_lottery_data(
                max_pages=max_pages,
                target_count=target_count
            )
            
            if result['success']:
                total_count = LotteryResult.query.count()
                print(f"数据更新完成，新增{result['total_added']}条记录，总计{total_count}条")
                return jsonify({
                    'message': result['message'],
                    'new_count': result['total_added'],
                    'total_count': total_count,
                    'total_skipped': result['total_skipped'],
                    'pages_crawled': result['pages_crawled']
                }), 200
            else:
                return jsonify({'error': result['error']}), 500
            
        except Exception as e:
            print(f"更新数据失败: {e}")
            return jsonify({'error': f'更新失败: {str(e)}'}), 500
    
    # AI分析路由
    @ai_bp.route('/analyze', methods=['POST'])
    # @jwt_required()  # 临时注释掉JWT认证
    def analyze_data():
        try:
            data = request.get_json()
            if not data:
                return jsonify({'error': '请求数据为空'}), 400
            
            start_draw = data.get('start_draw')
            end_draw = data.get('end_draw')
            custom_prompt = data.get('prompt', '')  # 获取自定义提示词
            
            # 添加调试日志
            print(f"[DEBUG] 接收到的数据: {data}")
            print(f"[DEBUG] custom_prompt: '{custom_prompt}'")
            
            if not start_draw or not end_draw:
                return jsonify({'error': '开始期数和结束期数不能为空'}), 400
            
            # 获取历史数据
            lottery_data = LotteryResult.query.filter(
                LotteryResult.draw_number >= start_draw,
                LotteryResult.draw_number <= end_draw
            ).order_by(LotteryResult.draw_date.asc()).all()
            
            print(f"[DEBUG] 查询条件: start_draw={start_draw}, end_draw={end_draw}")
            print(f"[DEBUG] 查询到的数据量: {len(lottery_data)}")
            if lottery_data:
                print(f"[DEBUG] 数据范围: {lottery_data[0].draw_number} - {lottery_data[-1].draw_number}")
            
            if not lottery_data:
                return jsonify({'error': '没有找到历史数据'}), 400
            
            # 检查数据量，避免分析过多数据导致超时
            if len(lottery_data) > 100:
                return jsonify({'error': '分析数据量过大，请选择不超过100期的数据'}), 413
            
            print(f"[DEBUG] 开始AI分析，数据量: {len(lottery_data)}期")
            
            # 获取互斥关系数据
            exclusion_analysis = analyze_red_ball_exclusion(lottery_data)
            print(f"[DEBUG] 互斥分析完成，强互斥: {len(exclusion_analysis['strong_exclusions'])}, 弱互斥: {len(exclusion_analysis['weak_exclusions'])}")
            
            # 调用AI分析，传递自定义提示词和互斥关系
            try:
                ai_result = call_deepseek_ai(lottery_data, custom_prompt, exclusion_analysis)
                print(f"[DEBUG] AI分析完成，预测数量: {len(ai_result['predictions'])}")
            except Exception as ai_error:
                print(f"[DEBUG] AI分析出错: {ai_error}")
                # 如果AI分析失败，使用备选方案
                fallback_result = fallback_prediction(lottery_data, exclusion_analysis)
                ai_result = {
                    'predictions': fallback_result['predictions'],
                    'analysis': fallback_result['analysis'],
                    'prompt': f"备选方案：基于{len(lottery_data)}期历史数据",
                    'ai_response': '使用备选预测方案',
                    'ai_model': 'fallback',
                    'analysis_process': f"AI调用失败，使用备选方案生成预测"
                }
                print(f"[DEBUG] 使用备选方案，预测数量: {len(ai_result['predictions'])}")
            
            # 保存预测记录
            prediction_record = AIPrediction(
                start_draw=start_draw,
                end_draw=end_draw,
                data_count=len(lottery_data),
                predicted_numbers=json.dumps(ai_result['predictions']),
                analysis_result=ai_result['analysis']
            )
            
            # 设置新增的字段
            prediction_record.prompt = ai_result['prompt']
            prediction_record.ai_model = ai_result['ai_model']
            prediction_record.ai_response = json.dumps(ai_result['ai_response'], ensure_ascii=False) if isinstance(ai_result['ai_response'], dict) else str(ai_result['ai_response'])
            prediction_record.analysis_process = ai_result['analysis_process']
            
            # 保存互斥关系分析数据
            # if exclusion_analysis:
                # prediction_record.set_exclusion_analysis(exclusion_analysis)
            db.session.add(prediction_record)
            db.session.commit()
            
            print(f"[DEBUG] 预测记录已保存，ID: {prediction_record.id}")
            
            return jsonify({
                'predictions': ai_result['predictions'],
                'analysis': ai_result['analysis'],
                'prediction_id': prediction_record.id,
                'data_count': len(lottery_data),
                'ai_model': ai_result['ai_model'],
                'prompt': ai_result['prompt'][:200] + '...' if len(ai_result['prompt']) > 200 else ai_result['prompt']  # 截断过长的prompt
            }), 200
            
        except Exception as e:
            db.session.rollback()
            print(f"AI分析失败: {e}")
            import traceback
            traceback.print_exc()
            return jsonify({'error': f'分析失败: {str(e)}'}), 500
    
    @ai_bp.route('/mutual-exclusion', methods=['POST'])
    # @jwt_required()  # 临时注释掉JWT认证
    def analyze_mutual_exclusion():
        """分析双色球红球互斥关系"""
        try:
            data = request.get_json()
            if not data:
                return jsonify({'error': '请求数据为空'}), 400
            
            period_count = data.get('period_count', 50)  # 默认分析50期
            start_draw = data.get('start_draw')  # 起始期数
            
            # 根据是否指定起始期数来获取数据
            if start_draw:
                # 从指定期数开始，获取后续N期数据
                recent_data = LotteryResult.query.filter(
                    LotteryResult.draw_number >= start_draw
                ).order_by(LotteryResult.draw_date.asc()).limit(period_count).all()
                
                if not recent_data:
                    return jsonify({'error': f'没有找到从期数{start_draw}开始的数据'}), 400
            else:
                # 获取最近N期的数据
                recent_data = LotteryResult.query.order_by(LotteryResult.draw_date.desc()).limit(period_count).all()
                
                if not recent_data:
                    return jsonify({'error': '没有找到历史数据'}), 400
            
            # 分析互斥关系
            exclusion_analysis = analyze_red_ball_exclusion(recent_data)
            
            return jsonify({
                'success': True,
                'period_count': len(recent_data),
                'start_draw': start_draw,
                'date_range': {
                    'start_date': recent_data[0].draw_date.isoformat(),
                    'end_date': recent_data[-1].draw_date.isoformat()
                },
                'analysis': exclusion_analysis
            }), 200
            
        except Exception as e:
            print(f"互斥分析失败: {e}")
            return jsonify({'error': f'分析失败: {str(e)}'}), 500
    
    @ai_bp.route('/verify', methods=['POST'])
    @jwt_required()
    def verify_prediction():
        try:
            data = request.get_json()
            if not data:
                return jsonify({'error': '请求数据为空'}), 400
            
            prediction_id = data.get('prediction_id')
            if not prediction_id:
                return jsonify({'error': '预测ID不能为空'}), 400
            
            prediction = AIPrediction.query.get(prediction_id)
            if not prediction:
                return jsonify({'error': '预测记录不存在'}), 404
            
            next_draw_number = get_next_draw_number(prediction.end_draw)
            actual_result = LotteryResult.query.filter_by(draw_number=next_draw_number).first()
            if not actual_result:
                return jsonify({'error': f'期号 {next_draw_number} 的开奖结果尚未公布'}), 400
            
            predicted_numbers = json.loads(prediction.predicted_numbers)
            actual_red_balls = [
                actual_result.red_ball_1, actual_result.red_ball_2, actual_result.red_ball_3,
                actual_result.red_ball_4, actual_result.red_ball_5, actual_result.red_ball_6
            ]
            actual_blue_ball = actual_result.blue_ball
            
            verification_results = []
            total_win_amount = 0
            
            for pred in predicted_numbers:
                red_balls = pred['red_balls']
                blue_ball = pred['blue_ball']
                
                matched_red_balls = [ball for ball in red_balls if ball in actual_red_balls]
                matched_red_count = len(matched_red_balls)
                matched_blue_ball = blue_ball == actual_blue_ball
                
                win_level, win_amount = calculate_win_level(matched_red_count, matched_blue_ball, actual_result.prize_info)
                
                verification_results.append({
                    'red_balls': red_balls,
                    'blue_ball': blue_ball,
                    'matched_red_balls': matched_red_balls,
                    'matched_red_count': matched_red_count,
                    'matched_blue_ball': matched_blue_ball,
                    'win_level': win_level,
                    'win_amount': win_amount
                })
                
                total_win_amount += win_amount
            
            prediction.actual_result = json.dumps({
                'draw_number': next_draw_number,
                'draw_date': actual_result.draw_date.isoformat(),
                'actual_red_balls': actual_red_balls,
                'actual_blue_ball': actual_blue_ball,
                'verification_results': verification_results,
                'total_win_amount': total_win_amount,
                'prize_info': actual_result.prize_info
            })
            prediction.win_amount = total_win_amount
            prediction.win_info = f"中奖{len([r for r in verification_results if r['win_level'] > 0])}组，总金额¥{total_win_amount}"
            
            print(f"验证预测ID {prediction_id}: 总中奖金额 = {total_win_amount}")
            print(f"验证结果: {verification_results}")
            
            db.session.commit()
            
            db.session.refresh(prediction)
            print(f"更新后的win_amount: {prediction.win_amount}")
            
            return jsonify({
                'success': True,
                'prediction': {
                    'id': prediction.id,
                    'actual_result': prediction.actual_result,
                    'win_amount': float(prediction.win_amount),
                    'win_info': prediction.win_info
                },
                'verification_result': {
                    'draw_number': next_draw_number,
                    'actual_red_balls': actual_red_balls,
                    'actual_blue_ball': actual_blue_ball,
                    'predictions': verification_results,
                    'total_win_amount': total_win_amount
                }
            }), 200
            
        except Exception as e:
            db.session.rollback()
            print(f"验证预测失败: {e}")
            return jsonify({'error': f'验证失败: {str(e)}'}), 500
    
    @ai_bp.route('/predictions', methods=['GET'])
    # @jwt_required()  # 临时注释掉JWT认证
    def get_predictions():
        try:
            page = request.args.get('page', 1, type=int)
            per_page = request.args.get('per_page', 20, type=int)
            
            pagination = AIPrediction.query.order_by(AIPrediction.created_at.desc()).paginate(
                page=page, per_page=per_page, error_out=False
            )
            
            result_data = []
            for item in pagination.items:
                predicted_numbers = []
                try:
                    if item.predicted_numbers:
                        predicted_numbers = json.loads(item.predicted_numbers)
                except:
                    predicted_numbers = []
                
                actual_result = None
                try:
                    if item.actual_result:
                        actual_result = json.loads(item.actual_result)
                    else:
                        next_draw_number = get_next_draw_number(item.end_draw)
                        actual_lottery = LotteryResult.query.filter_by(draw_number=next_draw_number).first()
                        if actual_lottery:
                            actual_red_balls = [
                                actual_lottery.red_ball_1, actual_lottery.red_ball_2, actual_lottery.red_ball_3,
                                actual_lottery.red_ball_4, actual_lottery.red_ball_5, actual_lottery.red_ball_6
                            ]
                            actual_blue_ball = actual_lottery.blue_ball
                            
                            verification_results = []
                            total_win_amount = 0
                            
                            for pred in predicted_numbers:
                                red_balls = pred['red_balls']
                                blue_ball = pred['blue_ball']
                                
                                matched_red_balls = [ball for ball in red_balls if ball in actual_red_balls]
                                matched_red_count = len(matched_red_balls)
                                matched_blue_ball = blue_ball == actual_blue_ball
                                
                                win_level, win_amount = calculate_win_level(matched_red_count, matched_blue_ball, actual_lottery.prize_info)
                                
                                verification_results.append({
                                    'red_balls': red_balls,
                                    'blue_ball': blue_ball,
                                    'matched_red_balls': matched_red_balls,
                                    'matched_red_count': matched_red_count,
                                    'matched_blue_ball': matched_blue_ball,
                                    'win_level': win_level,
                                    'win_amount': win_amount
                                })
                                
                                total_win_amount += win_amount
                            
                            actual_result = {
                                'draw_number': next_draw_number,
                                'draw_date': actual_lottery.draw_date.isoformat(),
                                'actual_red_balls': actual_red_balls,
                                'actual_blue_ball': actual_blue_ball,
                                'verification_results': verification_results,
                                'total_win_amount': total_win_amount,
                                'prize_info': actual_lottery.prize_info
                            }
                except Exception as e:
                    print(f"解析实际结果失败: {e}")
                    actual_result = None
                
                db_win_amount = float(item.win_amount) if item.win_amount else 0
                actual_win_amount = 0
                if actual_result and 'total_win_amount' in actual_result:
                    actual_win_amount = actual_result['total_win_amount']
                
                final_win_amount = max(db_win_amount, actual_win_amount)
                
                print(f"预测ID {item.id}: 数据库win_amount={db_win_amount}, actual_win_amount={actual_win_amount}, 最终={final_win_amount}")
                
                result_data.append({
                    'id': item.id,
                    'start_draw': item.start_draw,
                    'end_draw': item.end_draw,
                    'data_count': item.data_count,
                    'predicted_numbers': predicted_numbers,
                    'actual_result': actual_result,
                    'win_amount': final_win_amount,
                    'win_info': item.win_info,
                    'analysis_result': item.analysis_result,
                    'created_at': item.created_at.isoformat() if item.created_at else None
                })
            
            return jsonify({
                'data': result_data,
                'total': pagination.total,
                'pages': pagination.pages,
                'current_page': page
            }), 200
            
        except Exception as e:
            print(f"获取预测历史失败: {e}")
            return jsonify({'error': f'获取预测失败: {str(e)}'}), 500

    @reports_bp.route('/winning-analysis', methods=['GET'])
    @jwt_required()
    def get_winning_analysis():
        try:
            # 这里添加具体的业务逻辑
            analysis_data = {
                "message": "This is a sample winning analysis."
            }
            return jsonify(analysis_data), 200
        except Exception as e:
            print(f"获取中奖分析数据失败: {e}")
            return jsonify({'error': f'获取中奖分析数据失败: {str(e)}'}), 500

    @reports_bp.route('/prediction-trends', methods=['GET'])
    @jwt_required()
    def get_prediction_trends():
        """获取预测趋势报表"""
        # 处理OPTIONS请求
        if request.method == 'OPTIONS':
            return '', 200

        try:
            print('开始获取预测趋势报表')
            # 获取最近30天的预测数据
            thirty_days_ago = datetime.now() - timedelta(days=30)

            # AIPrediction = get_ai_prediction_model()
            # 按日期统计预测次数
            daily_stats = db.session.query(
                func.date(AIPrediction.created_at).label('date'),
                func.count(AIPrediction.id).label('count')
            ).filter(
                AIPrediction.created_at >= thirty_days_ago
            ).group_by(
                func.date(AIPrediction.created_at)
            ).order_by(
                func.date(AIPrediction.created_at)
            ).all()

            # 按日期统计中奖情况
            # daily_wins = db.session.query(
            #     func.date(AIPrediction.created_at).label('date'),
            #     func.sum(func.case([(AIPrediction.win_amount > 0, 1)], else_=0)).label('wins'),
            #     func.sum(AIPrediction.win_amount).label('amount')
            # ).filter(
            #     AIPrediction.created_at >= thirty_days_ago,
            #     AIPrediction.actual_result.isnot(None)
            # ).group_by(
            #     func.date(AIPrediction.created_at)
            # ).order_by(
            #     func.date(AIPrediction.created_at)
            # ).all()

            # 按日期统计中奖情况 - 使用最兼容的写法
            daily_wins = db.session.query(
                func.date(AIPrediction.created_at).label('date'),
                func.sum(func.cast(AIPrediction.win_amount > 0, db.Integer)).label('wins'),
                func.sum(AIPrediction.win_amount).label('amount')
            ).filter(
                AIPrediction.created_at >= thirty_days_ago,
                AIPrediction.actual_result.isnot(None)
            ).group_by(
                func.date(AIPrediction.created_at)
            ).order_by(
                func.date(AIPrediction.created_at)
            ).all()

            # 合并数据
            trends = {}
            for stat in daily_stats:
                date_str = stat.date.strftime('%Y-%m-%d')
                trends[date_str] = {
                    'date': date_str,
                    'predictions': stat.count,
                    'wins': 0,
                    'amount': 0
                }

            for win in daily_wins:
                date_str = win.date.strftime('%Y-%m-%d')
                if date_str in trends:
                    trends[date_str]['wins'] = win.wins
                    trends[date_str]['amount'] = float(win.amount) if win.amount else 0

            result = {'trends': list(trends.values())}
            print(f'预测趋势报表获取成功: {len(trends)}天数据')
            return jsonify(result), 200
        except Exception as e:
            print(f"获取中奖分析数据失败: {e}")
            return jsonify({'error': f'获取中奖分析数据失败: {str(e)}'}), 500


    # 报表路由
    @reports_bp.route('/summary', methods=['GET'])
    @jwt_required()
    def get_summary():
        try:
            total_predictions = AIPrediction.query.count()
            verified_predictions = AIPrediction.query.filter(
                AIPrediction.actual_result.isnot(None)
            ).count()
            
            total_win_amount = db.session.query(func.sum(AIPrediction.win_amount)).scalar() or 0
            
            verified_predictions_list = AIPrediction.query.filter(
                AIPrediction.actual_result.isnot(None)
            ).all()
            
            win_count = sum(1 for pred in verified_predictions_list if pred.win_amount and float(pred.win_amount) > 0)
            win_rate = (win_count / len(verified_predictions_list) * 100) if verified_predictions_list else 0
            
            seven_days_ago = datetime.now() - timedelta(days=7)
            recent_predictions = AIPrediction.query.filter(
                AIPrediction.created_at >= seven_days_ago
            ).count()
            
            return jsonify({
                'total_predictions': total_predictions,
                'verified_predictions': verified_predictions,
                'total_win_amount': float(total_win_amount),
                'win_rate': round(win_rate, 2),
                'recent_predictions': recent_predictions,
                'total_lottery_data': LotteryResult.query.count()
            }), 200
            
        except Exception as e:
            print(f"获取汇总报表错误: {e}")
            return jsonify({'error': f'获取汇总失败: {str(e)}'}), 500
    
    # 注册蓝图
    app.register_blueprint(auth_bp, url_prefix='/api/auth')
    app.register_blueprint(lottery_bp, url_prefix='/api/lottery')
    app.register_blueprint(ai_bp, url_prefix='/api/ai')
    app.register_blueprint(reports_bp, url_prefix='/api/reports')
    
    # 注册爬取服务蓝图
    # from backend.api.lottery_crawler_api import crawler_bp
    # app.register_blueprint(crawler_bp, url_prefix='/api/crawler')
    
    # 错误处理
    @app.errorhandler(404)
    def not_found_error(error):
        return jsonify({'error': '页面未找到'}), 404
    
    @app.errorhandler(500)
    def internal_error(error):
        db.session.rollback()
        return jsonify({'error': '服务器内部错误'}), 500
    
    # 创建数据库表
    with app.app_context():
        db.create_all()
        print("✓ 数据库表创建完成")
    
    if __name__ == '__main__':
        print("=" * 50)
        print("AI双色球分析助手 - 后端服务")
        print("=" * 50)
        print("访问地址: http://localhost:5000")
        print("API文档: http://localhost:5000/api/")
        print("=" * 50)
        
        # 强制使用生产模式，避免Windows路径问题
        print("使用生产模式启动，避免debug模式路径问题...")
        app.run(host='0.0.0.0', port=5000, debug=False)

if __name__ == '__main__':
    main() 